﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace ExceptionMessageBoxLibrary
{
    /// <summary>
    /// MessageBox to show detail of Exception.
    /// </summary>
    /// <typeparam name="T">Customize View or Dialog Window to show exception, which implements IExceptionMessageBoxView</typeparam>
    public class ExceptionMessageBox<T> where T : IExceptionMessageBoxView, new()
    {
        const string defaultCaption = "Exception Message";        

        public static MessageBoxResult Show(Exception p_exception)
        {
            return ShowCore(p_exception.Message, p_exception, defaultCaption, MessageBoxButton.OK, null);
        }

        public static MessageBoxResult Show(String p_message, Exception p_exception)
        {
            return ShowCore(p_message, p_exception, defaultCaption, MessageBoxButton.OK, null);
        }

        public static MessageBoxResult Show(String p_message, Exception p_exception, Window p_owner)
        {
            return ShowCore(p_message, p_exception, defaultCaption, MessageBoxButton.OK, p_owner);
        }

        public static MessageBoxResult Show(String p_message, Exception p_exception, String p_caption, MessageBoxButton p_button, Window p_owner)
        {
            return ShowCore(p_message, p_exception, p_caption, p_button, p_owner);
        }

        /// <summary>
        /// Core Messagebox Show method.
        /// <remarks>Basic implementation logic is separated and hide in this method, so that messagebox behavior or messagebox dependencyobject can be changed without impact to Show methods.</remarks>
        /// </summary>
        /// <param name="p_message">custom message</param>
        /// <param name="p_exception">exception to be shown as additional information</param>
        /// <param name="p_caption">caption of messagebox</param>
        /// <param name="p_button">buttons on messagebox</param>
        /// <returns></returns>
        private static MessageBoxResult ShowCore(String p_message, Exception p_exception, String p_caption, MessageBoxButton p_button, Window p_owner)
        {
            if (p_message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (p_caption == null)
            {
                throw new ArgumentNullException("caption");
            }

            if (p_owner == null && Application.Current != null) p_owner = Application.Current.MainWindow;

            String l_message = GetDetailMessage(p_exception);

            IExceptionMessageBoxView view = new T();

            view.Model = new ExceptionMessageBoxViewModel()
            {
                Caption = p_caption,
                UserMessage = p_message,
                ExceptionDetail = l_message,
                MessageBoxButton = p_button
            };


            return view.ShowExceptionMessage(p_owner);
        }

        private static String GetDetailMessage(Exception p_exception)
        {
            StringBuilder l_messageBuilder = new StringBuilder();
            l_messageBuilder.AppendLine("An exception has occured. Please see details.");
            l_messageBuilder.Append(Environment.NewLine);

            l_messageBuilder.Append(GetExceptionDetail(p_exception));

            String l_message = l_messageBuilder.ToString();
            return l_message;
        }

        public static String GetExceptionDetail(Exception ex)
        {
            StringBuilder l_exceptionDetailBuffer = new StringBuilder();

            if (ex.InnerException != null)
            {
                l_exceptionDetailBuffer.Append(GetExceptionDetail(ex.InnerException));
            }

            Type exceptionType = ex.GetType();

            l_exceptionDetailBuffer.Append('[');
            l_exceptionDetailBuffer.Append(exceptionType.Name);
            l_exceptionDetailBuffer.Append(": ");
            l_exceptionDetailBuffer.Append(ex.Message);
            l_exceptionDetailBuffer.Append(']');
            l_exceptionDetailBuffer.Append(Environment.NewLine);

            l_exceptionDetailBuffer.AppendLine(ex.StackTrace);

            return l_exceptionDetailBuffer.ToString();
        }

    }
}
